package com.hylanda.processors.hlMailSenderPlus;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import net.minidev.json.JSONObject;

import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by GuoMeng on 2019/1/8.
 */
public class MailService {
    protected hlMailSenderProcessor mHlMailSenderProcessor;

    protected String server;
    protected String port;
    protected boolean isSSL;
    protected String usr;
    protected String pwd;
    protected Session session;

    protected String mailTo;
    protected String mailCc;
    protected String mailBcc;
    protected String mailTpl;
    protected String mailAttr;
    protected String[] mailOutput;

    public MailService( MailConfig _conf, hlMailSenderProcessor _hlMail_senderProcessor) throws RuntimeException{
        mHlMailSenderProcessor = _hlMail_senderProcessor;
        server      = _conf.getValue( MailConfig.SMTP_SERVER );
        port        = _conf.getValue( MailConfig.SMTP_PORT );
        isSSL       = _conf.getValue( MailConfig.SMTP_SSL ).equals( "1" );
        usr         = _conf.getValue( MailConfig.SMTP_USER );
        pwd         = _conf.getValue( MailConfig.SMTP_PWD );

        mailTo      = _conf.getValue( MailConfig.SEND_TO );
        mailCc      = _conf.getValue( MailConfig.SEND_CC );
        mailBcc     = _conf.getValue( MailConfig.SEND_BCC );

        mailAttr    = _conf.getValue( MailConfig.MAIL_ATTR );

        String _outPut  = _conf.getValue( MailConfig.MAIL_OUTPUT );
        mailOutput  = ( null == _outPut || _outPut.equals( "null" ) || _outPut.isEmpty() ) ? null : _conf.getValue( MailConfig.MAIL_OUTPUT ).split( "," );

        // TODO: 2019/1/9   邮件样式模板，未来该参数可能自来与用户选择，前台会根据用户选择的模板来提示如何填写MESSAGE模板
        mailTpl = "default";

        Properties props    = new Properties();
        props.setProperty( "mail.transport.protocol", "smtp" ); // 使用的协议（JavaMail规范要求）
        props.setProperty( "mail.smtp.host", server ); // 发件人的邮箱的 SMTP 服务器地址
        props.setProperty( "mail.smtp.port", port );
        props.setProperty( "mail.smtp.auth", "true" );
        props.setProperty( "mail.smtp.timeout", MailConfig.SMTP_TIMEOUT );
        if( isSSL ){
            props.put( "mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory" );
            props.setProperty( "mail.smtp.auth", "true" ); // 需要请求认证
            props.setProperty( "mail.smtp.ssl.enable", "true" );// 开启ssl
            props.setProperty( "mail.smtp.ssl.checkserveridentity", "false" );
        }
        session     = Session.getInstance( props );  // 根据邮件配置创建会话，注意session别导错包
        session.setDebug( false );   // 开启debug模式，可以看到更多详细的输入日志
    }

    /**
     * SMTP连接测试
     * @return
     */
    public boolean test(){
        Transport transport = null;
        try{
            transport = session.getTransport();
            transport.connect( server, usr, pwd );
            transport.close();
        }catch( Exception e ){
            mHlMailSenderProcessor.writeLog( "SMTP SERVER CONNECT FAILD! srv:" + server + "; usr:" + usr + "; pwd:" + pwd );
            return false;
        }finally {
            try {
                if( null != transport )
                    transport.close();
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * 邮件发送处理
     * @param mData
     * @return
     * @throws RuntimeException
     */
    protected Integer send( MailData mData ) throws RuntimeException{
        Transport transport     = null;
        try{
            HashMap<String, Object> oData   = mData.make();
            mHlMailSenderProcessor.writeLog( "LOAD MAIL TPL SUCCESSED!" );
            String sMailContent             = makeMailContent( MailTpl.def, oData );

            MimeMessage msg                 = new MimeMessage( session );
            MimeMultipart msgMultipart      = new MimeMultipart("mixed" );
            msg.setContent( msgMultipart );

            setFrom         ( msg, usr );
            addRecipient    ( msg, mailTo, "to" );
            addRecipient    ( msg, mailCc, "cc" );
            addRecipient    ( msg, mailBcc, "bcc" );
            setSubject      ( msg, String.valueOf( oData.get( MailConfig.MAIL_SUBJECT ) ) );
            setContent      ( msgMultipart, sMailContent, "text/html;charset=utf-8" );
            setAttr         ( msgMultipart, mData, mailAttr );
            mHlMailSenderProcessor.writeLog( "MAKE MAIL SUCCESSED!" );
            msg.setSentDate( new Date() );
            msg.saveChanges();

            transport                       = session.getTransport();
            transport.connect( server, usr, pwd );
            mHlMailSenderProcessor.writeLog( "SERVER CONNECT SUCCESSED!" );
            transport.sendMessage( msg, msg.getAllRecipients() );

            mHlMailSenderProcessor.writeLog( "SEND MAIL SUCCESSED!" );
            mHlMailSenderProcessor.getConfig().setLastSendTime( null );
            mHlMailSenderProcessor.writeLog( "REST MAIL TIMER" );
            transport.close();
            mHlMailSenderProcessor.writeLog( "SERVER CLOSE!" );
            mData.clearData();
        }catch( Exception e ){
            mHlMailSenderProcessor.writeLog( "MAIL SEND FAILD!" + e.getMessage() );
            mHlMailSenderProcessor.getConfig().setLastSendTime( e.getMessage() );
            mHlMailSenderProcessor.writeLog( "REST MAIL TIMER BEFORE ERROR!" );
            e.printStackTrace();
            /*if( e.getMessage().startsWith( "460" ) ){
                throw new RuntimeException( "MAIL SEND FAILD!" + e.getMessage() );
            }*/
        }finally {
            try {
                if( null != transport )
                    transport.close();
            } catch (MessagingException e) {
                mHlMailSenderProcessor.writeLog( "SERVER CLOSE FAILD!" + e.getMessage() );
            }
        }
        return 1;
    }

    /**
     * 发件人设置
     * @param msg
     * @param mailFrom
     */
    protected void setFrom( MimeMessage msg, String mailFrom ){
        try {
            msg.setFrom( new InternetAddress( mailFrom ) );
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 收件人设置
     * @param msg
     * @param mailTo
     */
    protected void addRecipient( MimeMessage msg, String mailTo, String rType ){
        if( !mailTo.isEmpty() && !mailTo.toLowerCase().equals( "null" )){
            List<String> _aMailTo       = Arrays.asList( mailTo.split( "," ) );
            List<InternetAddress> _adds = new ArrayList<>();
            for( String _s : _aMailTo ){
                if( _s.isEmpty() )
                    continue;
                try {
                    _adds.add( new InternetAddress( _s ) );
                } catch( MessagingException e ){
                    e.printStackTrace();
                }
            }
            if( _adds.size() > 0 ){
                InternetAddress[] _list     = _adds.toArray( new InternetAddress[_adds.size()] );
                Message.RecipientType _to   = null;
                switch( rType ){
                    case "to"   :
                        _to = Message.RecipientType.TO;
                        break;
                    case "cc"   :
                        _to = Message.RecipientType.CC;
                        break;
                    case "bcc"   :
                        _to = Message.RecipientType.BCC;
                        break;
                }
                if( null != _to ){
                    try {
                        msg.setRecipients( _to, _list );
                    } catch (MessagingException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 设置邮件主题
     * @param msg
     * @param subject
     */
    protected void setSubject( MimeMessage msg, String subject ){
        try {
            msg.setSubject( subject, "utf-8" );
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置邮件内容
     * @param msgMultipart
     * @param message
     * @param format
     */
    protected void setContent( MimeMultipart msgMultipart, String message, String format ){
        try {
            MimeBodyPart content        = new MimeBodyPart();
            MimeMultipart bodyMultipart = new MimeMultipart("related");
            MimeBodyPart htmlPart       = new MimeBodyPart();
            msgMultipart.addBodyPart( content );
            content.setContent( bodyMultipart );
            bodyMultipart.addBodyPart( htmlPart );
            htmlPart.setContent( message, format );
        } catch( MessagingException e ){
            e.printStackTrace();
        }
    }

    /**
     * 添加附件
     * @param msgMultipart
     * @param data
     * @param type
     */
    protected void setAttr( MimeMultipart msgMultipart, MailData data, String type ){
        byte[] content          = null;
        String sMimeType        = "";
        String sExtFName        = "";

        switch( type ){
            case "excel" :
                content     = makeExcelAttr( data );
                sMimeType   = "application/vnd.ms-excel";
                sExtFName   = ".xls";
                break;
        }

        if( content != null ){
            try {
                MimeBodyPart mBodyPart       = new MimeBodyPart();
                mBodyPart.setDataHandler( new DataHandler( content, sMimeType ) );
                mBodyPart.setFileName( "ALLDATA_" + new SimpleDateFormat( "yyyy-MM-dd_HH" ).format( new Date() ) + sExtFName );
                msgMultipart.addBodyPart( mBodyPart );
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
    }

    protected byte[] makeExcelAttr( MailData mData ){
        byte[] rst = null;
        try {
            ByteArrayOutputStream _out  = new ByteArrayOutputStream();
            ExcelWriter _writer         = new ExcelWriter( _out, ExcelTypeEnum.XLS, false );
            Sheet _sh1                  = new Sheet( 1, 0 );
            _sh1.setSheetName( "sheet1" );
            List<List<String>> _ls      = new ArrayList<>();

            List<String> _keySet        = new ArrayList<>();
            _keySet.addAll( mData.keySet() );
            if( null != mailOutput && mailOutput.length != 0 ){
                _keySet.clear();
                _keySet.addAll( Arrays.asList( mailOutput ) );
            }

            List<String> firstLine      = new ArrayList<>();
            AtomicInteger _index        = new AtomicInteger( 1 );
            firstLine.add( "序号" );    //序号补丁
            firstLine.addAll( _keySet );

            _ls.add( firstLine );
            for( JSONObject _data : mData.getAll() ){
                List<String> _tmp   = new ArrayList<>();
                _tmp.add( String.valueOf( _index.getAndIncrement() ) );
                for( String _k : _keySet ){
                    String _v       = _data.getAsString( _k );
                    if( null == _v ){
                        _v      = "";
                    }
                    try{
                        if( _v.length() >= 32768 )
                            _tmp.add( _v == null ? "" : _v.substring( 0, 32767 ) );
                        else
                            _tmp.add( _v == null ? "" : _v );
                    }catch( Exception e ){
                        mHlMailSenderProcessor.writeLog( "SET COL ERROR!" + e.getMessage() );
                    }
                }
                _ls.add( _tmp );
            }
            _writer.write0( _ls, _sh1 );
            _writer.finish();
            rst     = _out.toByteArray();
            _out.close();
        } catch (FileNotFoundException e) {
            mHlMailSenderProcessor.writeLog( "SET MALL CONTEXT ERROR!" + e.getMessage() );
        } catch (IOException e) {
            mHlMailSenderProcessor.writeLog( "SET MALL CONTEXT ERROR!" + e.getMessage() );
        }
        return rst;
    }

    /**
     * 格式化邮件内容
     * @param tpl
     * @param oData
     * @return
     */
    protected String makeMailContent( String tpl, HashMap<String, Object> oData ){
        String sMailText    = String.valueOf( oData.get( MailConfig.MAIL_MESSAGE ) );
        String sMailCount   = String.valueOf( oData.get( MailConfig.DATA_STAT ) );
        String sRst         = new String( tpl ).replaceAll( "%count%", sMailCount );
        sRst                = sRst.replaceAll( "%numlimit%", MailData.quoteReplacement( String.valueOf( oData.get( MailConfig.MAIL_LIMIT ) ) ) );
        sRst                = sRst.replaceAll( "%maildata%", MailData.quoteReplacement( sMailText ) );
        return sRst;
    }
}
